package cn.xiaosiyuan.util.XMLFile;

import cn.xiaosiyuan.util.X;
import cn.xiaosiyuan.util.interfaces.IXMLUtil;
import org.w3c.dom.*;
import cn.xiaosiyuan.util.genId.PKGenerator;

import java.io.File;
import java.util.*;

public class XmlUtil implements IXMLUtil {

    /**
     *
     * 一行一个 map，然后按照从上到下的顺序，逐行把 map 放到 list 里面
     *
     * 递归解析XML 文件的 把标签名 和 属性值 存入到 list里面，并且每一个map里面存入 id 和 parent_id 来记录 map直接的上下级关系
     *
     * @param -    list 生成的一个带有 id 和 parent_id 的list
     * @param path 文件的绝对路径，目前只支持绝对路径
     */
    public List<Map<String, String>> parseXMLToList(String path) {
        // LinkedList 会保证顺序
        List<Map<String, String>> list = new LinkedList<>();
        // 读XML文件
        Document document = cn.hutool.core.util.XmlUtil.readXML(new File(path));
        Element element = document.getDocumentElement();
        // 第一次调用，就是第一级，parent_id 就给空
        parseElement(list, element, "", "0");
        return list;
    }

    /**
     * 递归解析 XML 文件
     * <p>
     * 解析第一级
     * 生成唯一主键 id 然后 parent_id 为空
     * <p>
     * 解析第二级
     * 生成唯一主键 id 然后 parent_id 赋值为上一级 id
     * <p>
     * 增加 level 记录层级，从0开始计数
     * <p>
     * <p>
     * TagName： billMenu-config 没有属性，所以输出空
     *
     * @param element  xml文件的 元素
     * @param parentId 第一级没有 parentId 所以调用的时候给 空
     *                 例子：parseElement(element,"");
     * @param level    层级，0表示第一级，1表示第二级，以此类推
     */
    private void parseElement(List<Map<String, String>> list, Element element, String parentId, String level) {
        // 设置id来记录上下级关系
        // 主键生成器
        String id = PKGenerator.newId();

        Map<String, String> elementMap = new HashMap();

        // 拿到当前element的所有的属性名和属性值
        NamedNodeMap namedNodeMap = element.getAttributes();
        // 遍历复制给firstMap存起来
        for (int i = 0; i < namedNodeMap.getLength(); i++) {
            Attr attr = (Attr) namedNodeMap.item(i);
            elementMap.put(attr.getName(), attr.getValue());
        }
        // 把标签名也记录下来
        elementMap.put("TagName", element.getTagName());
        // 把 id 放到 map 里面
        elementMap.put("id", id);
        elementMap.put("parent_id", parentId);
        // 层级数
        elementMap.put("level", level);
        list.add(elementMap);
        // 此注释，↓方便调试，不要删除
        /*System.out.println(elementMap.toString());*/

        // 拿到当前element的子节点集合
        NodeList nodeList = element.getChildNodes();
        Node childNode;
        // 有可能没有子节点,做一个非空判断
        if (nodeList.getLength() != 0) {
            // 如果有下级，层级加1，赋值给下一级，不能写在for循环里面
            level = String.valueOf(Integer.parseInt(level) + 1);
            // 遍历当前element的所有的子节点
            for (int i = 0; i < nodeList.getLength(); i++) {
                childNode = nodeList.item(i);
                if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                    parseElement(list, (Element) childNode, id, level);
                }
            }
        }
    }



    /**
     * 标签，一个map里面只有一个标签
     */
    public static final String TAG_NAME = "TagName";

    /**
     * 属性
     */
    // 通用属性
    public static final String ATTR_COMMON_LEVEL = "level";
    public static final String ATTR_COMMON_PARENT_ID = "parent_id";
    public static final String ATTR_COMMON_ID = "id";

    // SQL—xml 的属性（attribute）
    // 表名的属性
    // 表名
    public static final String ATTR_TABLE_ENTITY_NAME = "entity-name";
    // 表注释
    public static final String ATTR_TABLE_TITLE = "title";
    // extends 关键字
    public static final String ATTR_TABLE_EXTENDS = "extends";


    // 字段属性
    // 字段名
    public static final String ATTR_FIELD_NAME = "name";
    // 字段类型
    public static final String ATTR_FIELD_TYPE = "type";
    // 字段注释
    public static final String ATTR_FIELD_DESC = "description";
    // 指定主键字段
    public static final String ATTR_FIELD_FIELD = "field";


    // 标签类型
    // 实体
    public static final String TAG_TYPE_ENTITY = "entity";
    // 抽象实体
    public static final String TAG_TYPE_ABS_ENTITY = "abs-entity";
    // 字段
    public static final String TAG_TYPE_FIELD = "field";
    // 主键字段
    public static final String TAG_TYPE_PRIM_KEY = "prim-key";




    /**
     * 就是把 list 按照 entity，拆分成几个小 list
     */
    public HashMap<String,List<Map<String, String>>> parseSqlXML(String path) {

        HashMap<String,List<Map<String, String>>> rs = new HashMap<>();
        List<Map<String, String>> list = parseXMLToList(path);
        if (list.size() <= 0) return rs;

        // 只循环一遍，就需要 abs-entity 必须在 entity 上面。
        // 这里循环两遍，用性能换易用性
        HashMap<String, List<Map<String, String>>> keyAbsEntity = getKeyAbsEntity(list);
        HashMap<String, List<Map<String, String>>> keyEntity = getKeyEntity(list, keyAbsEntity);
        return rs = keyEntity;
    }


    private HashMap<String,List<Map<String, String>>> getKeyAbsEntity(List<Map<String, String>> list) {
        if (list.size() <= 0) return null;

        HashMap<String,List<Map<String, String>>> key_AbsEntity = new HashMap<>();
        String preId = "", preLevel = "0", preAbsEntityName = "";
        Map<String, String> absEntityMap = new HashMap<>();
        for (Map<String, String> map : list) {
            String tagName = map.getOrDefault(TAG_NAME, "");

            String attrCommonId = map.getOrDefault(ATTR_COMMON_ID, "");
            String attrCommonLevel = map.getOrDefault(ATTR_COMMON_LEVEL, "");
            String attrCommonParentId = map.getOrDefault(ATTR_COMMON_PARENT_ID, "");

            String attrEntityName = map.getOrDefault(ATTR_TABLE_ENTITY_NAME, "");
            String attrEntityTitle = map.getOrDefault(ATTR_TABLE_TITLE, "");
            String attrEntityExtends = map.getOrDefault(ATTR_TABLE_EXTENDS, "");


            String attrFieldName = map.getOrDefault(ATTR_FIELD_NAME, "");
            String attrFieldType = map.getOrDefault(ATTR_FIELD_TYPE, "");
            String attrFieldDesc = map.getOrDefault(ATTR_FIELD_DESC, "");


            switch(tagName){
                case TAG_TYPE_ABS_ENTITY: {
                    // 业务逻辑
                    preId = attrCommonId;
                    preLevel = attrCommonLevel;
                    preAbsEntityName = attrEntityName;
                    break;
                }
                case TAG_TYPE_FIELD: {
                    if (attrCommonParentId.equals(preId) && Integer.parseInt(attrCommonLevel) == Integer.parseInt(preLevel) + 1) {
                        List<Map<String, String>> absEntity = key_AbsEntity.getOrDefault(preAbsEntityName, null);
                        if (absEntity == null) {
                            absEntity = new ArrayList<>();
                            key_AbsEntity.put(preAbsEntityName, absEntity);
                        }

                        absEntity.add(map);
                    }
                }
                default:
                    break;
            }

        }

        return key_AbsEntity;
    }

    private HashMap<String,List<Map<String, String>>> getKeyEntity(List<Map<String, String>> list, HashMap<String,List<Map<String, String>>> keyAbsEntity) {
        if (list.size() <= 0) return null;
        if (keyAbsEntity == null) return null;

        HashMap<String,List<Map<String, String>>> key_Entity = new LinkedHashMap<>();
        String preId = "", preLevel = "";
        String preEntityName = "";
        for (Map<String, String> map : list) {
            String tagName = map.getOrDefault(TAG_NAME, "");

            String attrCommonId = map.getOrDefault(ATTR_COMMON_ID, "");
            String attrCommonLevel = map.getOrDefault(ATTR_COMMON_LEVEL, "");
            String attrCommonParentId = map.getOrDefault(ATTR_COMMON_PARENT_ID, "");

            String attrEntityName = map.getOrDefault(ATTR_TABLE_ENTITY_NAME, "");
            String attrEntityTitle = map.getOrDefault(ATTR_TABLE_TITLE, "");
            String attrEntityExtends = map.getOrDefault(ATTR_TABLE_EXTENDS, "");

            String attrFieldName = map.getOrDefault(ATTR_FIELD_NAME, "");
            String attrFieldType = map.getOrDefault(ATTR_FIELD_TYPE, "");
            String attrFieldDesc = map.getOrDefault(ATTR_FIELD_DESC, "");


            switch(tagName){
                case TAG_TYPE_ENTITY: {
                    // 业务逻辑
                    preId = attrCommonId;
                    preLevel = attrCommonLevel;
                    preEntityName = attrEntityName;

                    List<Map<String, String>> entity = key_Entity.getOrDefault(attrEntityName, null);
                    if (entity == null) {
                        entity = new ArrayList<>();
                        key_Entity.put(attrEntityName, entity);
                    }
                    entity.add(map);
                    List<Map<String, String>> absList = keyAbsEntity.getOrDefault(attrEntityExtends, null);
                    if (absList != null)    entity.addAll(absList);
                    break;
                }
                case TAG_TYPE_PRIM_KEY:
                case TAG_TYPE_FIELD: {
                    if (attrCommonParentId.equals(preId) && Integer.parseInt(attrCommonLevel) == Integer.parseInt(preLevel) + 1) {
                        List<Map<String, String>> entity = key_Entity.getOrDefault(preEntityName, null);
                        if (entity == null) {
                            entity = new ArrayList<>();
                            key_Entity.put(preEntityName, entity);
                        }

                        entity.add(map);
                    }
                }
                default:
                    break;
            }

        }
        return key_Entity;
    }

    public String getValue(String realPath, String tagName) {
        String value = "";
        List<Map<String, String>> list = X.xmlUtil.parseXMLToList(realPath);
        for (Map<String, String> map : list) {
            if (map.containsKey("key") && map.get("key").equalsIgnoreCase(tagName)) {
                value = map.getOrDefault("value", "");
                break;
            }
        }
        return value;
    }

}
